import React from "react";
import { getActiveItemStyleByName } from "containers/data-center/report/graphic-report/echarts-data-transfer/utils";
import { EventUtils, messages } from "share/common";
import { message } from 'antd';
import Condition from 'components/condition';
import "styles/data-center/report/graphic-report/vscroll-echart.scss";
import ReportWrapper from "components/template/graphic-report/report-wrapper"

const { If } = Condition;

const { PropTypes, Component } = React;

/**
 * 重构版内置分页柱状图
 *
 */

@ReportWrapper
class VscrollChartsV2 extends Component {
  constructor(props) {
    super(props);
    this.chart = null;
    //被点击的数据
    this.activeItem = null;
    //每个 canvas 显示条目，默认 10
    this.pageSize = 10;
    //虚拟滚动条的位置
    this.padding = 20;

    this.moveStart = 0;

    this.bindEvent = null;

    this.state = {
      cursor: 0,
      scrollSize: 0,
      scrollBarHeight: 0,
      optionsCopy: null
    }
  }

  //绘制图表
  //挂载组件到父级组件
  componentDidMount() {
    const { onRef, options, reportKey } = this.props;
    onRef && onRef({ ref: this, reportKey });
    let optionsCopy = this.createOptionsCopy();
    let optionsLength = options.yAxis[0].data.length;
    if (optionsLength > this.pageSize) {
      this.initVirtualScroll(optionsLength);
      this.initScrollEvent(true)
    } else {
      this.initScrollEvent(false)
    }
    this.drawChart(optionsCopy);
  }

  componentDidUpdate(prevProps) {
    if (prevProps.options !== this.props.options) {
      let optionsCopy = this.createOptionsCopy();
      let optionsLength = this.props.options.yAxis[0].data.length;
      let cursor = 0;

      // 初始化分页
      if (optionsLength > this.pageSize) {
        this.initVirtualScroll(optionsLength);
        this.initScrollEvent(true);
        cursor = this.findCursor(this.activeItem, optionsLength, this.pageSize);  // 自动寻找当前激活项的定位
        this.setState({
          cursor
        });
      } else {
        this.setState({
          cursor,
          scrollSize: 0,
          scrollBarHeight: 0,
        });
        this.initScrollEvent(false)
      }
      this.drawChart(optionsCopy, this.props.options, cursor);
    }
  }

  componentWillUnmount() {
    this.chart.dispose();
  }

  getCurrentRenderOptions(cursor, pageSize, options, optionsCopy) {
    let start = cursor;
    let len = options.yAxis[0].data.length;
    if (len <= pageSize) {
      optionsCopy.yAxis[0].data = [...options.yAxis[0].data];
      optionsCopy.series.map((seriesItem, index) => {
        seriesItem.data = [...options.series[index].data]
      })
      this.setState({
        optionsCopy
      });
      return optionsCopy
    }

    if (cursor + pageSize >= len) {
      start = len - pageSize
    }
    optionsCopy.yAxis[0].data = options.yAxis[0].data.slice(start, start + pageSize);
    optionsCopy.series.map((seriesItem, index) => {
      seriesItem.data = options.series[index].data.slice(start, start + pageSize);
    })
    this.setState({
      optionsCopy
    });
    return optionsCopy;
  }

  initScrollEvent(register) {
    const { container, scrollBar } = this.refs;
    if (register && !this.registered) {
      EventUtils.addHandler(container, 'mousewheel', this.onMouseWheel, true);
      EventUtils.addHandler(container, 'DOMMouseScroll', this.onMouseWheel, true);
      EventUtils.addHandler(scrollBar, 'mousedown', this.onMouseDown, true);
      this.registered = true;
    } else if (!register) {
      EventUtils.removeHandler(container, 'mousewheel', this.onMouseWheel, true);
      EventUtils.removeHandler(container, 'DOMMouseScroll', this.onMouseWheel, true);
      EventUtils.removeHandler(scrollBar, 'mousedown', this.onMouseDown, true);
      this.registered = false;
    }
  }

  initVirtualScroll(optionsLength) {
    function _getScrollBarHeight(wrapper, scrollSize, padding) {
      return (wrapper.clientHeight - padding) / (scrollSize + 1) + padding
    }

    function _getScrollSize(optionsLength, pageSize) {
      return optionsLength - pageSize
    }

    let { scrollWrapper } = this.refs,
      scrollSize = _getScrollSize(optionsLength, this.pageSize),
      scrollBarHeight = _getScrollBarHeight(scrollWrapper, scrollSize, this.padding);
    this.setState({
      scrollSize,
      scrollBarHeight
    });
  };

  findCursor(activeItem, optionsLength, pageSize) {
    let cursor = 0;
    if (activeItem && optionsLength > pageSize) {
      let { data } = activeItem;
      let targetIndex;
      let target = this.props.options.series[0].data.find((item, index) => {
        let equal = false;
        if (typeof item.criteria === 'object') {
          equal = JSON.stringify(item.criteria) === JSON.stringify(data.criteria)
        } else {
          equal = item.criteria === data.criteria;
        }
        return equal && ((targetIndex = index) || true)
      });
      if (target && targetIndex !== undefined) {
        cursor = targetIndex >= this.pageSize ? targetIndex - this.pageSize + 1 : 0;
      } else {
        this.setActiveItem(null);
      }
    }
    return cursor;
  }

  // 创建options副本，用于避免分页直接修改原options
  createOptionsCopy() {
    const { options } = this.props;
    let optionsCopy = Object.assign({}, options);
    optionsCopy.yAxis = Object.assign([], options.yAxis);
    for (let i = 0; i < optionsCopy.yAxis.length; i++) {
      optionsCopy.yAxis[i] = Object.assign({}, options.yAxis[i]);
      optionsCopy.yAxis[i].data = []
    }
    optionsCopy.series = Object.assign([], options.series);
    for (let i = 0; i < optionsCopy.series.length; i++) {
      optionsCopy.series[i] = Object.assign({}, options.series[i]);
      optionsCopy.series[i].data = []
    }
    return optionsCopy
  }

  drawChart(optionsCopy, nextOptions, cursor = 0) {
    const dom = this.refs.chart;
    if (!dom) return;
    let { options, compareKey, allowActivated } = this.props;
    options = nextOptions || options;
    if (!echarts.getInstanceByDom(dom)) {
      this.chart = echarts.init(dom, "helios");
    }
    // //第一次绘制
    if (options && this.chart) {
      //设置滚动条高度
      let renderOptions = this.getCurrentRenderOptions(cursor, this.pageSize, options, optionsCopy);
      if (this.activeItem) {
        renderOptions.series.map(seriesItem => {
          seriesItem.itemStyle = getActiveItemStyleByName(this.activeItem, renderOptions, compareKey)
        })
      } else {
        renderOptions.series.map(seriesItem => {
          seriesItem.itemStyle = null
        })
      }
      this.chart.setOption(renderOptions);
      if (allowActivated && !this.bindEvent) {
        this.chart.on('click', this.bindEvent = (item) => {
          if (this.props.isFetchingData || !allowActivated) {
            this.props.isFetchingData && message.warning(messages('common-1.key56')/*正在加载，请稍等...*/);
            return;
          }
          if (item.color === "#00386b") {
            this.setActiveItem(null);
          } else {
            this.setActiveItem(item);
          }
          this.drawChart(this.state.optionsCopy, undefined, this.state.cursor);
        });
      }
    }
  }

  setActiveItem = (item, onlySet) => {
    let needEmit = this.activeItem !== item;
    this.activeItem = item;
    if (needEmit && !onlySet) {
      let { chartIndex, reportKey } = this.props;
      let active = item && item.color !== "#00386b";
      this.props.onActivatedItemChange({
        active,
        item,
        chartIndex,
        reportKey
      });
    }
  };

  clearActiveItem = () => {
    this.setActiveItem(null, true);
  };

  clearActiveItemAndRedraw = () => {
    this.setActiveItem(null, true);
    this.drawChart(this.state.optionsCopy, undefined, this.state.cursor);
  };

  onMouseWheel = (e) => {
    e = EventUtils.getEvent(e);
    EventUtils.preventDefault(e);

    let delta = (e.wheelDelta && (e.wheelDelta > 0 ? 1 : -1)) || (e.detail && (e.detail > 0 ? -1 : 1));

    let { cursor, scrollSize, optionsCopy } = this.state;
    const oldCursor = cursor;
    cursor -= delta;

    if (cursor <= 0) {
      cursor = 0;
    }
    if (cursor >= scrollSize) {
      cursor = scrollSize;
    }

    if (cursor === oldCursor) return;

    this.setState({
      cursor,
    });

    this.drawChart(optionsCopy, undefined, cursor);
  };

  onMouseDown = (e) => {
    e = EventUtils.getEvent(e);
    EventUtils.preventDefault(e);
    this.moveStart = e.clientY;
    EventUtils.addHandler(document, 'mousemove', this.onMouseMove, true);
    EventUtils.addHandler(document, 'mouseup', this.onMouseUp, true);
  };

  onMouseMove = (e) => {
    e = EventUtils.getEvent(e);
    EventUtils.preventDefault(e);
    let { scrollBarHeight, cursor, optionsCopy, scrollSize } = this.state;
    let threshold = scrollBarHeight - this.padding;
    let delta = e.clientY - this.moveStart;
    let changeCursor = 0;
    if (Math.abs(delta) > threshold) {
      changeCursor = Math.floor(delta / threshold);
    } else {
      return;
    }
    const oldCursor = cursor;
    cursor += changeCursor;

    // 禁止超出边界
    if (cursor <= 0) {
      cursor = 0;
    }
    if (cursor >= scrollSize) {
      cursor = scrollSize;
    }
    changeCursor = cursor - oldCursor;

    // 边界情况
    if (cursor === oldCursor) {
      this.moveStart = e.clientY;
      return
    }
    this.moveStart = this.moveStart + changeCursor * threshold;
    this.setState({
      cursor,
    });
    this.drawChart(optionsCopy, undefined, cursor);
  };

  onMouseUp = (e) => {
    e = EventUtils.getEvent(e);
    EventUtils.preventDefault(e);
    this.moveStart = 0;
    EventUtils.removeHandler(document, 'mouseup', this.onMouseUp, true);
    EventUtils.removeHandler(document, 'mousemove', this.onMouseMove, true);
  };

  render() {
    const { width, height, className, options } = this.props;
    const { cursor, scrollBarHeight } = this.state;
    const showVirtualScroll = options.yAxis[0].data.length > this.pageSize;
    const scrollBarStyle = {
      height: scrollBarHeight + 'px',
      top: cursor * (scrollBarHeight - this.padding) + 'px'
    };
    return (
      <div ref="container"
           className='vscroll-echart'
           style={{
             height: height + 'px'
           }}>
        <div>
          <div ref="chart"
               className={className}
               style={{ height, width }}>
          </div>
        </div>
        <If value={showVirtualScroll}>
          <div className='chart-vscroll-wrap'>
            <div className="vscroll-wrap"
                 ref="scrollWrapper">
              <div className="vscroll"
                   ref="scrollBar"
                   style={scrollBarStyle}>
              </div>
            </div>
          </div>
        </If>
      </div>
    );
  }

  static propTypes = {
    options: PropTypes.object,
    height: PropTypes.number,
    width: PropTypes.number,
    onRef: PropTypes.any,
    chartIndex: PropTypes.any,//成本中心图表序号
    allowActivated: PropTypes.bool, // 是否允许选中
    onActivatedItemChange: PropTypes.func,
    reportKey: PropTypes.string,
    isFetchingData: PropTypes.bool,
    compareKey: PropTypes.any, // 用于比较选中项与options
  }

  static defaultProps = {
    height: 324,
    onActivatedItemChange: () => {
    },
  }
}

export default VscrollChartsV2;
